import { any } from "../../../core/logic";
import { Compute } from "./Compute";
import { sharp } from "./shaders/sharp";
import { Pass } from "../Pass";
import { Engine } from "../../../Engine";
import { guid } from "../../../core/utils";
/**
 * @class
 * @memberof w.compute
 */
class SharpComputer extends Compute {
  constructor(opts = {}) {
    super(opts);
    this.initBuffer();
    this.initPipeLine();
    this.sharpFactor = any(opts.sharpFactor, 0.5);
    this.sharpPreBlurFactor = any(opts.sharpPreBlurFactor, 0.6);
  
  }
  set sharpFactor(v) {
    this._sharpFactor = v;
    Engine.instance.queue.writeBuffer(this.configBuffer, 0, new Float32Array([v]));
    this.update();
    return this;
  }
  get sharpFactor() {
    return this._sharpFactor;
  }
  set sharpPreBlurFactor(v) {
    this._sharpPreBlurFactor = v;
    Engine.instance.queue.writeBuffer(this.configBuffer, 4, new Float32Array([v]));
    this.update();
    return this;
  }
  get sharpPreBlurFactor() {
    return this._sharpPreBlurFactor;
  }
 
  initBuffer() {
    this.configBuffer = Engine.instance.device.createBuffer({
      label: "configBuffer",
      size: 2 * 4,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
    });
    this.sharpTex = Engine.instance.device.createTexture({
      label: "sharpTex",
      size: Engine.instance.size,
      format: "rgba16float",
      mipLevelCount: 1,
      sampleCount: 1,
      usage:
        GPUTextureUsage.STORAGE_BINDING |
        GPUTextureUsage.COPY_DST |
        GPUTextureUsage.COPY_SRC |
        GPUTextureUsage.TEXTURE_BINDING,
    });
    this.sharpTex.view=this.sharpTex.createView();
 
  }
  initPipeLine() {
    this.computePipeline = Engine.instance.device.createComputePipeline({
      layout: `auto`,
      compute: {
        module: Engine.instance.device.createShaderModule({
          code: sharp,
        }),
        entryPoint: "main",
      },
    });

  }
  initBindGroup(){
    if (this.sharpTex?.width !== Engine.instance.size[0] ||this.sharpTex?.height !== Engine.instance.size[1]){
      this.sharpTex.destroy();
      this.sharpTex=null;
    }
    if(!this.sharpTex){
      this.sharpTex =  Engine.instance.device.createTexture({
        size: Engine.instance.size,
        usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING,
        format: 'rgba16float',
      });
      this.sharpTex.view=this.sharpTex.createView();
      this.sharpTex.id=guid();
    }
    if(this.bindGroup && this.bindGroup.id!=this.sharpTex.id+Pass.instance().readAttach.id){
        this.bindGroup=null;
    }
    if(!this.bindGroup){
      this.bindGroup = Engine.instance.device.createBindGroup({
        layout:  this.computePipeline.getBindGroupLayout(0),
        entries: [
          {
            binding: 0,
            resource: {
              buffer: this.configBuffer,
            },
          },
          {
            binding: 1,
            resource: Pass.instance().readAttach.view,
          },
          {
            binding: 2,
            resource: this.sharpTex.view,
          },
        ],
      });
      this.bindGroup.id=this.sharpTex.id+Pass.instance().readAttach.id;
    }
    return this.bindGroup;
    
  }
  onCompute(commandEncoder) {
    this.initBindGroup()
    const workerSizeX = Math.ceil(Engine.instance.size[0] / 8);
    const workerSizeY = Math.ceil(Engine.instance.size[1] / 8);
    const workerSizeZ = 1;
    const computePass = commandEncoder.beginComputePass();
    computePass.setPipeline(this.computePipeline);
    computePass.setBindGroup(0, this.bindGroup);
    computePass.dispatchWorkgroups(workerSizeX,workerSizeY,workerSizeZ);
    computePass.end();
  }
}
export { SharpComputer };
